#pragma once
#include <carbon/core/error.h>
#include <carbon/core/optional.h>
#include <carbon/core/thread.h>
#include <carbon/core/block_queue.h>

CARBON_NS_BEGIN

/// @brief 通用任务队列线程池。
/// 
/// 基本功能说明：
/// 1. 支持设置线程名称、最大/最小线程数、任务队列容量（默认最小线程数*1024）
/// 2. 支持线程动态伸缩：
///     a. 初始启动最小个数的线程，并持续保持运行。
///     b. 当任务队列满时，支持动态新增线程，直到最大线程数。
///     c. 当线程一定空闲时间（可配置，默认30s)没有获取到任务，则按次序逐个退出（反向启动顺序），直到保证最小线程数。
class QueuedThreadPool final {
    CARBON_NONCOPYABLE(QueuedThreadPool);
    CARBON_NONMOVABLE(QueuedThreadPool);

    using ThreadVec = std::vector<carbon::Thread>;
    using TaskQueue = carbon::BlockingQueue<carbon::RunnableFn>;
    using AtomicInt = std::atomic<int>;

public:
    QueuedThreadPool() {}
    QueuedThreadPool(const std::string &name) : QueuedThreadPool(name, 8) {}
    QueuedThreadPool(const std::string &name, int maxThreads) : QueuedThreadPool(name, maxThreads, 1) {}
    QueuedThreadPool(const std::string &name, int maxThreads, int minThreads) : QueuedThreadPool(name, maxThreads, minThreads, 30) {}
    QueuedThreadPool(const std::string &name, int maxThreads, int minThreads, int idleTimeoutSecs) : QueuedThreadPool(name, maxThreads, minThreads, idleTimeoutSecs, minThreads * 1024) {}
    
    /// @brief 线程池构造
    /// @param name 线程池名称, 将设置到成员线程中。
    /// @param maxThreads 最大线程数，当任务积压过多时，线程数会动态增长到最大值，并在空闲时自动退出。
    /// @param minThreads 最小线程数，线程池保证有该数目的线程一直在运行或待命。
    /// @param idleTimeoutSecs 动态增长的线程空闲退出时间（秒）
    /// @param queueCapacity 任务队列的容量
    QueuedThreadPool(const std::string &name, int maxThreads, int minThreads, int idleTimeoutSecs, int taskCapacity)
    : m_name(name), m_max_threads(maxThreads), m_min_threads(minThreads), m_idle_timeout(idleTimeoutSecs), m_tasks(taskCapacity), m_threads(maxThreads) 
    {
        assert(m_min_threads <= m_max_threads);
    }

    /// 启动线程池
    bool start(carbon::Error * err = nullptr);

    /// 停止线程池。方法阻塞直到线程全部退出。
    void stop();

    bool execute(carbon::RunnableFn fn, carbon::Error * err = nullptr);
    bool execute(RunnableFn fn, std::chrono::milliseconds timeout, carbon::Error * err = nullptr);
private:
    bool startThread();                 // 尝试创建一个线程，返回是否创建成功。
    void joinThreads();                 // 等待线程退出并回收资源
    void threadRun(int threadIndex);    // 线程主函数

private:
    std::string     m_name;         // 线程池名称
    int             m_max_threads  {0};  // 最大线程数
    int             m_min_threads  {0};  // 最小线程数
    int             m_idle_timeout {-1};    // 线程空闲时间，动态线程在空闲一定时间后退出。秒
    volatile bool   m_need_stop    {false};
    AtomicInt       m_thread_count; // 当前活动线程数
    TaskQueue       m_tasks;        // 任务队列
    ThreadVec       m_threads;      // 线程列表
}; // QueuedThreadPool

CARBON_NS_END
